如何使用MAT进行JVM内存泄露分析
在《Java Agent的隔离实现以及卸载时一些坑》中,卸载Agent之后,使用 jmap-histo:live pid
命令验证执行FGC,相关Class是否会被回收,结果遇到了一些问题,最终通过MAT内存分析才定位到了问题,本文介绍如何使用MAT进行内存泄露分析。
MAT安装
MAT是eclipse中的一个插件,不过也提供了独立的版本,在IDEA风靡的今天,建议直接使用独立版本,官网下载地址
http://www.eclipse.org/mat/downloads.php
根据操作系统版本下载最新的MAT
MAT配置
找到MemoryAnalyzer.ini文件,该文件里面有个Xmx参数,该参数表示最大内存占用量,默认为1024m,根据堆转储文件大小修改该参数即可。
获取堆转储文件
1、如果想主动获取,可以使用jamp命令,对于部署到服务器上的程序可以采用这种方式,获取堆转储文件后scp到本地,然后本地分析。
jmap -dump:format=b,file=<dumpfile.hprof> <pid>
2、如果想在发生内存溢出的时候自动dump,需要添加下面参数
-XX:+HeapDumpOnOutOfMemoryError
MAT使用
打开MAT之后,加载dump文件,显示下面的界面。
一般用到比较多的2个功能 1、Histogram 2、Leak Suspects
Histogram
这个功能主要是查看类和对象关系,对象和对象之间的关系,用来定位哪些对象在FGC之后还活着,哪些对象占大部分内存。
1、点开Histogram,可列出每一个类的实例数,支持正则表达式查找,也可以计算出该类所有对象的retained size。
Shallow Heap就是对象本身占用内存的大小,不包含其引用的对象内存,实际分析中作用不大。常规对象(非数组)的ShallowSize由其成员变量的数量和类型决定。数组的shallow size有数组元素的类型(对象类型、基本类型)和数组长度决定。对象成员都是些引用,真正的内存都在堆上,看起来是一堆原生的byte[], char[], int[],对象本身的内存都很小。
Retained Heap值的计算方式是将Retained Set(当该对象被回收时那些将被GC回收的对象集合)中的所有对象大小叠加。或者说,因为X被释放,导致其它所有被释放对象(包括被递归释放的)所占的heap大小。
Retained Heap例子: 一个ArrayList对象持有100个对象,每一个占用16 bytes,如果这个list对象被回收,那么其中100个对象也可以被回收,可以回收16*100 + X的内存,X代表ArrayList的shallow大小。
所以,RetainedHeap可以更精确的反映一个对象实际占用的大小。
2、选择一个Class,右键选择List objects > with incoming references
在新页面会显示通过这个class创建的对象信息
3、选择一个对象,右键选择Path to GC Roots > **,通常在排查内存泄漏的时候,我们会选择exclude all phantom/weak/soft etc.references, 意思是查看排除虚引用/弱引用/软引用等的引用链,因为被虚引用/弱引用/软引用的对象可以直接被GC给回收,我们要看的就是某个对象否还存在Strong 引用链(在导出HeapDump之前要手动出发GC来保证),如果有,则说明存在内存泄漏,然后再去排查具体引用。
这时会拿到GC Roots到该对象的路径,通过对象之间的引用,可以清楚的看出这个对象没有被回收的原因,然后再去定位问题。
假如说上面对象此时本来应该是被GC掉的,简单的办法就是将其中的某处置为null或者remove掉,使其到GC Root无路径可达,处于不可触及状态,垃圾回收器就可以回收了。
Leak Suspects
Leak Suspects 界面提示可能存在内存的泄露。
然后接着,是问题一的描述,列出了一些比较大的实例。
点击Details可以看到细节信息
点开Details进入详情页面,在详情页面Shortest Paths To the Accumulation Point表示GC root到内存消耗聚集点的最短路径,如果某个内存消耗聚集点有路径到达GC root,则该内存消耗聚集点不会被当做垃圾被回收。
内存快照对比
为了有效的找出内存泄露的对象,一般会获取两个堆转储文件(先dump一个,隔段时间再dump一个),并同时打开两个dump文件。
打开其中一个Histogram,然后点击下面按钮。
选择另外一个需要对比的dump文件
通过对比结果可以方便的看出对象的变化情况,并快速定位问题。
还不会使用的MAT的同学,赶紧学起来,机会都是留给有准备的人。
-END-
近期热文:
缓存穿透、缓存并发、缓存失效之思路变迁
来之不易的美团面试,结果居然挂了...(附面试答案)
一文带你了解Java Agent
优秀开源框架的扩展机制,原来都是这样实现的...
蚂蚁金服中间件,一大波面经来袭!
【第二弹】21个让程序员泪流满面的瞬间
又发生频繁FGC,这次是谁的锅?
算法面试,如何在100 亿URL中判断某个URL是否存在?
百万并发下的Nginx性能优化之道,值得看!!!
多刷刷狼哥的博客,offer多多